/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkHttpServer.h"
#include "MkHttpSession.h"
#include "MkHttpResponse.h"
#include "MkHttpRequest.h"
#include "MkHttpUri.h"
#include "MkEvent/MkEvent.h"
#include "MkEvent/MkTimer.h"
#include "MkUtil/MkLog.h"
#include "MkUtil/MkTime.h"
#include "MkUtil/MkBase64.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkFile.h"

#ifdef _WIN32
#include <io.h>
#include <fcntl.h>
#ifndef stat
#define stat _stat
#endif
#ifndef fstat
#define fstat _fstat
#endif
#ifndef open
#define open _open
#endif
#ifndef close
#define close _close
#endif
#ifndef O_RDONLY
#define O_RDONLY _O_RDONLY
#endif
#endif /* _WIN32 */

const  MkString NotFoundString = "<html><head><title>404 Not Found</title></head><body bgcolor=\"white\"><center><h1>The resource you visited does not exist!</h1></center><hr><center>MkHttpServerV1.0</center></body></html>";
CMkHttpServer::CMkHttpServer(CMkEventPool* pEventPool, CMkTimer* pTimer)
    : CMkTcpServer(pEventPool, pTimer, 100000)
    , m_KeepAliveSeconds(60)
    , m_MaxKeepAliveRequests(1000)
{

}

CMkTcpSession* CMkHttpServer::CreateNewSession(CMkEvent *pEvent, CMkTimer* pTimer)
{
    //MkDebugLog("create new http session\n");
    return new CMkHttpSession(pEvent, pTimer, this);
}

Uint32 CMkHttpServer::OnSessionEventRemoved(CMkTcpSession* pSession)
{
    CMkHttpSession* pHttpSession = dynamic_cast<CMkHttpSession*>(pSession);
    if (pHttpSession && pHttpSession->IsWebSocket()) {
        OnWebsocketClosed(pHttpSession);
    }
    return CMkTcpServer::OnSessionEventRemoved(pSession);
}

Uint32 CMkHttpServer::SendResponse(const Uint64& HttpSessionId, const MkHttpStatusCode& Error, const MkHttpBodyType& BodyType/* = BodyTypeNone*/, const MkString& Body /*= ""*/)
{
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(HttpSessionId);
    if (it != m_MapTcpSession.end()) {
        CMkHttpSession *pSession = dynamic_cast<CMkHttpSession*>(it->second);
        if (pSession) {
            pSession->SendReply(Error, BodyType, Body);
        }
    }
    m_SessionLock.RUnlock();
    return NoneError;
}

Uint32 CMkHttpServer::SendDownloadResponse(const Uint64& HttpSession, FILE* pFile, Uint64 FileSize)
{
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(HttpSession);
    if (it != m_MapTcpSession.end()) {
        CMkHttpSession *pSession = dynamic_cast<CMkHttpSession*>(it->second);
        if (pSession) {
            pSession->SendFileReply(pFile, FileSize);
        }
    }
    m_SessionLock.RUnlock();
    return NoneError;
}

Uint32 CMkHttpServer::SendWebSocketText(const Uint64& HttpSessionId, const MkString& Msg)
{
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(HttpSessionId);
    if (it != m_MapTcpSession.end()) {
        CMkHttpSession *pSession = dynamic_cast<CMkHttpSession*>(it->second);
        if (pSession) {
            pSession->SendWebSocketText(Msg);
        }
    }
    m_SessionLock.RUnlock();
    return NoneError;
}

Uint32 CMkHttpServer::SendWebSocketBinary(const Uint64& HttpSessionId, const CMkBufferList& BufList, BOOL bMark/*=FALSE*/)
{
    //MkDebugLog("send ws session:%s\n", HttpSessionId.c_str());
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(HttpSessionId);
    if (it != m_MapTcpSession.end()) {
        CMkHttpSession *pSession = dynamic_cast<CMkHttpSession*>(it->second);
        if (pSession) {
            pSession->SendWebSocketBinary(BufList, bMark);
        }
    }
    m_SessionLock.RUnlock();
    return NoneError;
}

Uint32 CMkHttpServer::SendWebSocketClose(const Uint64& HttpSessionId)
{
    m_SessionLock.RLock();
    MapTcpSession::iterator it = m_MapTcpSession.find(HttpSessionId);
    if (it != m_MapTcpSession.end()) {
        CMkHttpSession *pSession = dynamic_cast<CMkHttpSession*>(it->second);
        if (pSession) {
            pSession->WebsocketSendClose();
        }
    }
    m_SessionLock.RUnlock();
    return NoneError;
}

CMkHttpServer::~CMkHttpServer()
{

}